/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_core.h                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2014/09/26 by songbb                               */
/*******************************************************************/

#ifndef __ORA_CORE_H_
#define __ORA_CORE_H_

#include <limits.h>

#include "frlist.h"
#include "frhash2.h"
#include "frstr.h"

#include "conntrack.h"
#include "module.h"
#include "frdb_cursor.h"
#include "frbyte_buffer.h"

#include "tns/ora_tns_type.h"

/* 标识符变量的初始化值 */
#define APM_ORA_FLAG_UNSET -1

/* Oracle模块哈希桶的最大尺寸 */
#define APM_ORA_HASH_SIZE 100

/* Oracle数据库表最大的列的个数 */
#define APM_ORA_MAX_COLUMNS 1000

/* Oracle 协议默认端口 */
#define APM_ORA_DEFAULT_PORT 1521

/* Oracle 会话过程数组最大值 */
#define APM_ORA_SESS_PHASE_MAX 16

/* Oracle 协议方向判断差值 */
#define APM_ORA_RESOLVE_DIRECT_BY 10

/* bitset操作 */
#define BITMASK(b) (1 << ((b) % CHAR_BIT))
#define BITSLOT(b) ((b) / CHAR_BIT)
#define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b))
#define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b))
#define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b))
#define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT)
#define BITLEN(a) (sizeof(a) / sizeof(char))

/* Oracle 会话过程 */
typedef enum __em_ora_sess_phase {
    APM_ORA_SESS_PHASE_INIT = 0,
    APM_ORA_SESS_PHASE_CONNECT,
    APM_ORA_SESS_PHASE_RESEND,
    APM_ORA_SESS_PHASE_REDIRECT,
    APM_ORA_SESS_PHASE_ACCEPT,
    APM_ORA_SESS_PHASE_SNS,
    APM_ORA_SESS_PHASE_PRO,
    APM_ORA_SESS_PHASE_DTY,
    APM_ORA_SESS_PHASE_LOG1,
    APM_ORA_SESS_PHASE_LOG2,
    APM_ORA_SESS_PHASE_OSESSKEY,
    APM_ORA_SESS_PHASE_OAUTH,
    APM_ORA_SESS_PHASE_OVERSION,
    APM_ORA_SESS_PHASE_OALL7,
    APM_ORA_SESS_PHASE_OALL8,
    APM_ORA_SESS_PHASE_FETCH,
    APM_ORA_SESS_PHASE_OOPEN,
    APM_ORA_SESS_PHASE_OCLOSE7,
    APM_ORA_SESS_PHASE_OCLOSE8,
    APM_ORA_SESS_PHASE_O80SES,
    APM_ORA_SESS_PHASE_ODNY,
    APM_ORA_SESS_PHASE_CANCEL7,
    APM_ORA_SESS_PHASE_COMMIT,
    APM_ORA_SESS_PHASE_ROLLBACK,
    APM_ORA_SESS_PHASE_LOB,
    APM_ORA_SESS_PHASE_LOGOFF,
} Ora_sess_phase;

/* Oracle游标结构体 */
typedef struct __st_ora_cursor
{
    unsigned long ul_cursor;
} Ora_cursor;

/* Oracle metadata结构体 */
typedef struct __st_ora_metadata
{
    short s_oacdty;
    short s_oacflg;
    short s_oacpre;
    short s_oacscl;
    int i_oacmxl;
    int i_oacmal;
    int i_oacfl2;
    int i_oacvsn;
    int i_oaccsi;
    short s_oaccsfrm;
    int i_oacmxlc;
} Ora_metadata;

/*
 *   L7session_ora 用于存放 oracle私有的session数据，对应L7_session的p_session_private变量
 *    通用的username、session_starttime、session_stoptime
 */
typedef struct __st_L7session_ora
{
    /* client基本信息 */
    char *p_client_hostname;                /* 客户端的主机名 */
    char *p_program;                        /* 客户端的程序名 */
    char *p_db_sid;                         /* 数据库的SID */
    char *p_username;                       /* 登录的用户名 */
    struct timeval st_logined_timestamp;    /* 用户登录成功的时间 */

    int i_use_oci;                          /* 是否使用oci接口 */
    int i_use_special_field;                /* 是否使用oci接口，参数主要用于调整通信协议中字段的多少（使用oci时，如果服务端使用大端，会被重新设置为非oci） */
    short s_tns_version_req;                /* TNS版本号，如310、311、312、313、314、315 */
    short s_tns_version;                    /* TNS版本号，如310、311、312、313、314、315 */
    short s_negotiated_options;             /* accept过程返回的options */
    int i_cli_is_bigendian;                 /* 有关客户端硬件设备大端小端的设置 */
    int i_srv_is_bigendian;                 /* 有关服务端硬件设备大端小端的设置 */
    char c_ttc_version;                     /* TTC版本号，如4、5、6、7 */
    char c_ttc_api_version;                 /* TTC API 版本号，7或者8 */
    char c_pro_srv_version;                 /* pro版本号，如4、5、6 */
    short s_ora_version;                    /* oracle版本号，如7230、8030、8100 */
    short s_version_number;                 /* OVersion版本 */
    int i_charset_assumed;
    short s_cli_charset_in;                 /* 客户端charset输入编码 */
    short s_cli_charset_out;                /* 客户端charset输出编码 */
    short s_srv_charset;                    /* 服务端charset编码 */
    short s_sdu;                            /* Session Data Unit Size */
    short s_srv_compile_time_capabilities_len;
    char *p_srv_compile_time_capabilities;
    short s_CTcap_len;
    char *p_CTcap;
    short s_RTcap_len;
    char *p_RTcap;
    int arr_ttc_type_rep[5];                /* 代表oracle.jdbc.ttc7.TTCTypeRep的rep参数 */
    char c_conversion_flags;                /* 代表oracle.jdbc.ttc7.TTCTypeRep的conversionFlags参数 */
    int i_srv_conversion;                   /* 代表oracle.jdbc.ttc7.TTCTypeRep的serverConversion参数 */
    int i_useCLR_big_chunks;                /* 代表oracle.jdbc.driver.T4CMAREngine的useCLRBigChunks参数 */
    int i_useLobPrefetch;                   /* 代表oracle.jdbc.driver.T4CConnection的useLobPrefetch参数 */

    int i_ptr_len;                          /* PTR的字节长度 */
    int i_detect_ptr_succ;                  /* 检测PTR的编码规则是否成功 */
    int i_send_typerep;                     /* OCI接口使用的是否是标准的oac字段，即并没有填充其他字段 */
    int i_c2snlsratio;                      /* TTCConversion的m_c2sNlsRatio属性*/
    int i_oci_stmt_req_skip4_ttc7;          /* 针对OCI ttc7接口方式请求的数据包中sqlLen字段后是否需要跳过4个字节的参数 */
    int i_oci_stmt_req_skip4_ttc8;          /* 针对OCI ttc8接口方式请求的数据包中sqlLen字段后是否需要跳过4个字节的参数 */
    int i_oci_oversion_skip4;
    int i_CHR_conversion_flags;
    int i_ttc7_oactoid;
    int i_ttc7_rxhrqsts;
    int i_ttc8_long_analyze_succ;
    int i_ttc8_stmt_req_i;
    int i_ttc8_stmt_req_j;
    int i_ttc8_stmt_req_dml;
    int i_ttc8_stmt_req_oci_after_dml;
    int i_ttc8_stmt_resp_dcb_recv;
    int i_ttc8_stmt_resp_oac_skip1;
    int i_ttc8_stmt_resp_oac_skipaftervsn;
    int i_ttc8_stmt_resp_udskpos;
    int i_ttc8_stmt_resp_udsflg;
    int i_ttc8_stmt_resp_dcbkm;
    int i_ttc8_stmt_resp_dcbni1;
    int i_ttc8_stmt_resp_dcbab2;
    int i_ttc8_stmt_resp_rpag;
    int i_ttc8_stmt_resp_rpadml;
    int i_ttc8_stmt_resp_oereocs;
    int i_ttc8_stmt_resp_oerendseq;
    int i_ttc8_stmt_resp_oeraij;
    int i_ttc8_stmt_resp_oci_oerskip8;
    int i_ttc8_stmt_resp_oci_oerskip6;

    int i_is_large_sdu;                     /* Oracle12c开始的session data size为large，通用包头则用前4个字节表示包长，否则用前2个字节表示包长 */
    int i_pool_enabled;                     /* 是否启用连接池的标志 1:启用 0:不启用 */

    unsigned long long ull_error_nums;
    unsigned long long ull_unfinshed_fragmented_packets;
    unsigned long long ull_packets_in;
    struct timeval st_timestamp;
    int i_closed_count;

    Ora_sess_phase arr_sess_phase[APM_ORA_SESS_PHASE_MAX]; /* Oracle 会话过程 */
    Frlist_header *p_list_closed_cursors;   /* 存储需要关闭的游标 Ora_cursor */

    unsigned long long ull_bits_phase_progress;
} L7session_ora;

/*
 *  Oracle请求数据
 */
typedef struct __st_L7_req_ora
{
    Sql_statement *p_st_stmt;               /* 临时存储新建的Sql_statement */
    Frlist_header *p_st_list_ttc7_stmt;
} L7_req_ora;

/*
 *  Oracle响应数据
 */
typedef struct __st_L7_resp_ora
{
    long l_response_code;                  /* 应答的状态码，存放数值，如 1403  */
    char *p_response_codestring;           /* 应答的状态码串，如ORA-01403 */
    char *p_response_error_mesg;           /* 应答的详细返回信息，如ORA-01403: 未找到任何数据*/
} L7_resp_ora;

/* 分片的状态 */
typedef enum __em_fragment_state {
    APM_ORA_FRAGMENT_INIT,
    APM_ORA_FRAGMENT_NEED_NEXT_REQ_PACKET,
    APM_ORA_FRAGMENT_NEED_NEXT_RESP_PACKET
} Ora_fragment_state;

/* Oracle数据包结构体 */
typedef struct __st_L7_ora_packet
{
    Ora_fragment_state fragment_state;  /* 当前的分片状态 */
    int i_is_request;                   /* 该包是否是请求包 -1:unset 1:request 0:response */
    Frbyte_Packet *p_st_packet;         /* 组包完成的数据 */
    unsigned int ui_len_to_read;        /* 还需要从下一个payload中读取多少个字节 */
    int i_is_first_packet;              /* 是否是第一个分片包 */
    char *p_payload_left;               /* 前一个包遗留的数据 */
    unsigned int ui_payload_left_len;   /* 前一个包遗留的数据长度 */
    unsigned int ui_length_orig;        /* 原始组包后的包的总长度，包含各个分片包的包头和dataflag */
    struct timeval st_timestamp_first;  /* 第一个请求的分片包的时间 */
    struct timeval st_timestamp_last;   /* 最后一个请求的分片包的时间 */
    Ora_tns_type tns_type;              /* TNS TYPE类型 */
    unsigned short us_dataflag;         /* DATAFLAG */
    int i_analyze_position;             /* 分析到的位置 */
    unsigned long ul_skip_len;
    int i_rpa_processed_flag;
    int i_rxh_processed_flag;
    int i_iov_processed_flag;
    int i_need_next_packet_lob;         /* 需要下一个分片包并且ttcCode为0x0e，这下一个分片包不带包头 */
} L7_ora_packet;

/* 存储当前会话的临时变量 */
typedef struct __st_L7_ora_curr_session
{
    unsigned long ul_cursor;                           /* 当前会话的游标 */
    int i_cursor_inrpa;
    unsigned int ui_batch_count;
    long long *p_ll_rows;
    int i_null_num;
    int i_rpa_processed_flag;
    int i_rxh_processed_flag;
    int i_iov_processed_flag;
    int i_bvc_found;                                   /* 当前会话是否检测到bvc */
    int i_bvc_num;                                     /* 当前会话bvc数 */
    char arr_columns_bit[BITNSLOTS(APM_ORA_MAX_COLUMNS)];      /* column的bit位设置 */
    int i_lob_source_locator_len;
    char c_lob_source_locator_6;
    char c_lob_source_locator_7;
    int i_lob_destination_locator_len;
    char c_lob_characterset;
    char c_lob_send_lob_amt;
    char c_lob_nullO2U;
} L7_ora_curr_session;

typedef struct __st_L7session_ora_private
{
    L7session_ora *p_st_sess;            /* session数据 */
    L7_req_ora *p_st_req;                /* request数据 */
    L7_resp_ora *p_st_resp;              /* response数据 */
    L7_ora_packet *p_st_ora_packet;      /* 当前处理中的Oracle数据包 */
    L7_ora_curr_session *p_st_curr_sess; /* 当前会话的临时性数据 */
    Frhash_header *p_hash_stmt;          /* statement数据 存放Sql_statement结构体 */
    L7_session *p_st_session;            /* 指向父级的L7_session结构体 */
} L7session_ora_private;

void ora_core_add_unfinshed_fragmented_packets(L7session_ora *p_st_sess);

#endif
